package jp.sourceforge.akjrcp.image.trimming;

import com.akjava.lib.standards.process.ProcessPrinter;

import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FigureListener;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.MouseMotionListener;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.imageio.ImageIO;

import jp.sourceforge.akjrcp.akj_betas.Akj_betasPlugin;
import jp.sourceforge.akjrcp.akj_betas.Messages;
import jp.sourceforge.akjrcp.commons.ui.AbstractFileDirChoicer.FileStatusChangeEvent;
import jp.sourceforge.akjrcp.commons.ui.AbstractFileDirChoicer.FileStatusChangeListener;
import jp.sourceforge.akjrcp.commons.ui.widget.WidgetBuilder;
import jp.sourceforge.akjrcp.commons.util.FileNameUtils;
import jp.sourceforge.akjrcp.image.clipboard.AutoClipboardSave;
import jp.sourceforge.akjrcp.image.clipboard.AutoSaveListener;
import jp.sourceforge.akjrcp.image.gifanime.GifAnimeMakeView;
import jp.sourceforge.akjrcp.ui.LayoutDataBuilder;
import jp.sourceforge.akjrcp.ui.SimpleImageCanvas;
import jp.sourceforge.akjrcp.ui.param.ParamBoolean;
import jp.sourceforge.akjrcp.ui.param.ParamItem;
import jp.sourceforge.akjrcp.ui.param.ParamItemActionListener;
import jp.sourceforge.akjrcp.ui.param.ParamRadioGroup;
import jp.sourceforge.akjrcp.ui.param.ParamScale;
import jp.sourceforge.akjrcp.util.ExecutingControler;
import jp.sourceforge.akjrcp.util.SelectionUtils;
import jp.sourceforge.akjrcp.util.StatusBarUtils;
import jp.sourceforge.akjrcp.util.ExecutingControler.ExecutingControlButton;
import jp.sourceforge.akjrcp.util.image.ImageUtils;

import org.apache.commons.lang.SystemUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class TrimmingView extends ViewPart {
	public static Log log=LogFactory.getLog(TrimmingView.class);
	
	public static final String ID = TrimmingView.class.getName();

	private jp.sourceforge.akjrcp.commons.ui.EditableFileList fileList;
	
	private TrimmingExecute executer;
	private jp.sourceforge.akjrcp.commons.ui.FileDirChoicer2 exportDirs;

	

	


	private SimpleImageCanvas imageCanvas;
	private FileSelected selectedListener=new FileSelected();

	private ParamBoolean clipSelect;

	private ParamRadioGroup exportType;

	private ExecutingControlButton execButton;

	private ParamScale jpegQualityScale;

	private FigureBoundsCntroler boundControler;
	private Label monitorLabel;
	private Button monitorButton;
	private Text baseNameText;
	private AutoClipboardSave autoSave;
	public void createPartControl(Composite parent) {
		parent.setLayout(new GridLayout());
		executer=new TrimmingExecute();
		Composite split2=WidgetBuilder.createGridLayoutComposite(parent,SWT.NULL,2,false);
		split2.setLayoutData(LayoutDataBuilder.fillBothGridData());
		fileList = WidgetBuilder.createFileList(split2,SWT.BORDER|SWT.MULTI,"*.gif;*.png;*.jpg;*.bmp");
		fileList.setLayoutData(LayoutDataBuilder.hintGridData(300, -1));
		fileList.setInput(this.getSite());
		fileList.addPropertyChangeListener(new IPropertyChangeListener(){

			public void propertyChange(PropertyChangeEvent event) {
				executer.updateControlSwitch();
			}});
		fileList.addSelectionChangedListener(new ISelectionChangedListener(){

			public void selectionChanged(SelectionChangedEvent event) {
				ISelection selection=event.getSelection();
				
				File selectFile=SelectionUtils.getSelectFile(selection);
				if(selectFile!=null){
					imageCanvas.setImagePath(selectFile.getAbsolutePath());
				}else{
					imageCanvas.setImagePath(null);
				}
			}});
		
		FigureMover mover=new FigureMover();
		
		imageCanvas = new SimpleImageCanvas(split2);
		imageCanvas.setLayoutData(LayoutDataBuilder.fillBothGridData());
		SelectAreaFigure selectionFigure= new SelectAreaFigure();
		
		selectionFigure.setBounds(new Rectangle(0,0,100,100));
		imageCanvas.getRootFigure().add(selectionFigure);
		
		mover.setTargetFigure(selectionFigure);
		
		Composite grid1=WidgetBuilder.createGridLayoutComposite(parent, SWT.NULL,4,false);
		//execute Button
		Composite exec_label=WidgetBuilder.createGridLayoutComposite(parent,SWT.NULL,2, false);
		execButton = new ExecutingControlButton(grid1,SWT.NULL,executer,
				Messages.getString("trimmingview.convert"),Messages.getString("cancel"));
		execButton.setLayoutData(LayoutDataBuilder.hintGridData(200,40));
		executer.updateControlSwitch();
		
		
		
		
		exportType = new ParamRadioGroup(grid1,SWT.NULL,"exportType",Messages.getString("trimmingview.exportType"),new String[]{"PNG","JPEG"},new String[]{"PNG","JPEG"},2);
		exportType.setParamItemActionListener(new UpdateButtonLabel());
		
		//quality.
		
		jpegQualityScale = new ParamScale(grid1,SWT.NULL,"jpeg_quality",Messages.getString("trimmingview.jpegQuality"),1,90,100);
		//baseName
		SimpleDateFormat format=new SimpleDateFormat("yyyyMMdd");
		
		
		
		Composite clips=WidgetBuilder.createGridLayoutComposite(parent, SWT.NULL,4,false);
		clipSelect = new ParamBoolean(clips,SWT.NULL,"clipSelect",Messages.getString("trimmingview.clipselect"));
		clipSelect.setParamItemActionListener(new UpdateButtonLabel());
		clipSelect.setValue(""+1);
		boundControler = new FigureBoundsCntroler(clips,SWT.NULL,selectionFigure);
		Composite exports=WidgetBuilder.createGridLayoutComposite(parent, SWT.NULL,3,false);
		exports.setLayoutData(LayoutDataBuilder.fillHorizontalGridData());
		WidgetBuilder.createLabel(exports, Messages.getString("trimmingview.baseName"));
		baseNameText = WidgetBuilder.createBorderText(exports,format.format(new Date()));
		baseNameText.setLayoutData(LayoutDataBuilder.hintGridData(100, 0));
		
		monitorLabel=WidgetBuilder.createLabel(clips, Messages.getString("trimmingview.status_stopped"));
		monitorButton=WidgetBuilder.createButton(clips, Messages.getString("trimmingview.start_monitor"));
		monitorButton.addSelectionListener(new SelectionListener(){

			public void widgetDefaultSelected(SelectionEvent e) {
			}

			public void widgetSelected(SelectionEvent e) {
					if(autoSave==null){
						autoSave=new AutoClipboardSave(SystemUtils.JAVA_IO_TMPDIR);
						autoSave.setDeleteOnExist(true);
						autoSave.startSave();
						autoSave.addAutoSaveListener(new MonitorImage());
						monitorLabel.setText(Messages.getString("trimmingview.status_monitoring"));
						monitorButton.setText(Messages.getString("trimmingview.stop_monitor"));
					}else{
						
						autoSave.stopSave();
						autoSave=null;
						monitorLabel.setText(Messages.getString("trimmingview.status_stopped"));
						monitorButton.setText(Messages.getString("trimmingview.start_monitor"));
					}
			}});
		
		//export quality & export type,
		exportDirs=WidgetBuilder.createDirectoryChoicerWithMyDesktopAndMyDocuments(exports, SWT.NULL, Messages.getString("trimmingview.export_dir"), false);
		
		exportDirs.addSelectableFileName(FileNameUtils.getMyPicturesPath());
		exportDirs.setFilePath(FileNameUtils.getMyPicturesPath());
		
		exportDirs.setLayoutData(LayoutDataBuilder.fillHorizontalGridData());
		exportDirs.addFileListChangeListener(selectedListener);//for update exec button
		
		updateLabel();
		
		//add menus
		WidgetBuilder.createSeparateMenu(fileList.getPopUpMenu());
		MenuItem addGifAnimeMenuItem=WidgetBuilder.createPushMenu(fileList.getPopUpMenu(),Messages.getString("trimmingview.add_gifanime"));
		addGifAnimeMenuItem.addSelectionListener(new SelectionListener(){

			public void widgetDefaultSelected(SelectionEvent e) {
				// TODO Auto-generated method stub
				
			}

			public void widgetSelected(SelectionEvent e) {
				
				if(executer.canExecute() && !executer.isExecuting()){
					executer.setAddGifAnimeView(true);
					executer.execute();
				}
				
			}});
	}
	
	public class MonitorImage implements AutoSaveListener{

		public void imageSaved(File file) {
			PlatformUI.getWorkbench().getDisplay().syncExec(new AddImage(file));
		}
		
	}
	
	public class AddImage extends Thread{
		File file;
		public AddImage(File file){
			this.file=file;
		}
		public void run(){
			fileList.addFile(file);//dont use add.
		}
	}
	
	public void updateLabel(){
		String label=exportType.getValue()+" "+Messages.getString("trimmingview.asimage")+" ";
		if(clipSelect.getBoolean()){
			label+=Messages.getString("trimmingview.convert");
		}else{
			label+=Messages.getString("trimmingview.convert_all");
		}
		execButton.setExecuteLabel(label);
	}
	//�؂蔲��
	//���ׂĂ͈̔͂�ۑ�
	public class UpdateButtonLabel implements ParamItemActionListener{
		public void paramItemModified(ParamItem item) {
			updateLabel();
		}
		
	}
	public void setFocus() {
		
	}
	
	 public final class FigureBoundsCntroler extends Composite{
		 private Text xInput,yInput,wInput,hInput;
		 private Figure targetFigure;
		 
		public int getX(){
			return targetFigure.getLocation().x;
		}
		public int getY(){
			return targetFigure.getLocation().y;
		}
		public int getWidth(){
			return targetFigure.getSize().width;
		}
		public int getHeight(){
			return targetFigure.getSize().height;
		}
		public FigureBoundsCntroler(Composite parent, int style,Figure targetFigure) {
			super(parent, style);
			setTargetFigure(targetFigure);
			
			this.setLayout(new GridLayout(8,false));
			Changed changed=new Changed();
			WidgetBuilder.createLabel(this,Messages.getString("x"));
			xInput=new Text(this,SWT.NULL);
			xInput.setLayoutData(LayoutDataBuilder.hintGridData(40, 0));
			xInput.addSelectionListener(changed);
			
			WidgetBuilder.createLabel(this,Messages.getString("y"));
			yInput=new Text(this,SWT.NULL);
			yInput.setLayoutData(LayoutDataBuilder.hintGridData(40, 0));
			yInput.addSelectionListener(changed);
			
			WidgetBuilder.createLabel(this,Messages.getString("width"));
			wInput=new Text(this,SWT.NULL);
			wInput.setLayoutData(LayoutDataBuilder.hintGridData(40, 0));
			wInput.addSelectionListener(changed);
			
			WidgetBuilder.createLabel(this,Messages.getString("height"));
			hInput=new Text(this,SWT.NULL);
			hInput.setLayoutData(LayoutDataBuilder.hintGridData(40, 0));
			hInput.addSelectionListener(changed);
			
		}
		public final class Changed implements SelectionListener{
			public void widgetDefaultSelected(SelectionEvent e) {
				if(targetFigure==null){
					log.warn("no target");
					return;
				}
				try{
				if(e.getSource()==xInput){
					int x=Integer.parseInt(xInput.getText());
					targetFigure.setLocation(new Point(x,targetFigure.getLocation().y));
				}else if(e.getSource()==yInput){
					int y=Integer.parseInt(yInput.getText());
					targetFigure.setLocation(new Point(targetFigure.getLocation().x,y));
				}else if(e.getSource()==wInput){
					int w=Integer.parseInt(wInput.getText());
					targetFigure.setSize(w,targetFigure.getSize().height);
				}else if(e.getSource()==hInput){
					int h=Integer.parseInt(hInput.getText());
					targetFigure.setSize(targetFigure.getSize().width,h);
				}
				}catch(Exception e2){
					e2.printStackTrace();
					log.warn("input wrong");
				}
			}

			public void widgetSelected(SelectionEvent e) {
				
			}
			
		}
		public Figure getTargetFigure() {
			return targetFigure;
		}
		public void setTargetFigure(Figure targetFigure) {
			this.targetFigure = targetFigure;
			targetFigure.addFigureListener(new FigureListener(){

				public void figureMoved(IFigure source) {
					updateBounds();
					
				}});
		}
		
		public void updateBounds(){
			xInput.setText(""+targetFigure.getLocation().x);
			yInput.setText(""+targetFigure.getLocation().y);
			wInput.setText(""+targetFigure.getSize().width);
			hInput.setText(""+targetFigure.getSize().height);
		}
		 
	 }
	 

	  public class FigureMover extends MouseMotionListener.Stub implements MouseListener{
		  private Figure currentFigure;
		  private Point lastPoint;
		  boolean resize;
		  
		  private Figure targetFigure;
		  public void setTargetFigure(Figure figure){
			  figure.addMouseListener(this);
			  figure.addMouseMotionListener(this);
			  if(figure.getParent()!=null){
			  figure.getParent().addMouseMotionListener(this);
			  }else{
				  log.warn("parent is null.maybe moving is bad");
			  }
			  targetFigure=figure;
		  }
		  public void move(int x,int y){
			  if(currentFigure!=null){
				  if(lastPoint!=null){
					  Point newPoint=new Point(x,y);
					  Dimension delta = newPoint.getDifference(lastPoint);
					  lastPoint = newPoint;
					  
					  if(resize){
					       		ResizableFigure f=(ResizableFigure) currentFigure;
					       		f.resize(delta.width,delta.height);
					       		//currentFigure.setSize(Math.max(f.getMinBounds().width,currentFigure.getBounds().width+delta.width),Math.max(f.getMinBounds().height,currentFigure.getBounds().height+delta.height));
					           }
					  else{
					  currentFigure.setBounds(currentFigure.getBounds().getTranslated(delta.width, delta.height));
					  }
				  }
			  }
		  }
		 
		public void moveOutSide(int x,int y){
			  if(currentFigure!=null){
				  if(!currentFigure.containsPoint(x, y)){
					
					  move(x,y);
				  }
			  }
		  }
		public void mouseDoubleClicked(MouseEvent arg0) {
			
		}
		
		 public void mouseDragged(MouseEvent me) { 
			 move(me.x,me.y);
		 }
		
		public void mousePressed(MouseEvent me) {
			if(currentFigure!=null){
				currentFigure.setBorder(null);
				
			}
			
			currentFigure=(Figure) me.getSource();
			
			//currentFigure.setBorder(new FocusBorder());
			
			lastPoint=new Point(me.x,me.y);
			if(currentFigure instanceof ResizableFigure){
				resize=((ResizableFigure)currentFigure).isResizeBox(lastPoint);
			}else{
				resize=false;
			}
			//figurePanel.repaint();
		}
		
		public void mouseReleased(MouseEvent arg0) {
			//currentFigure=null;
			
			lastPoint=null;
		}
	  }

	private class TrimmingExecute extends ExecutingControler{
		File[] files;
		String exportPath;
		float jpegQuality;
		boolean isPng;
		boolean isClip;
		private boolean cancelling=false;
		int clipX;
		int clipY;
		int clipW;
		int clipH;
		String baseName;
		
		boolean addGifAnimeView=false;
		File[] exportedFiles;
		@Override
		public void afterExecute() {
			if(addGifAnimeView){
				if(exportedFiles!=null){
					GifAnimeMakeView part;
					try {
						part = (GifAnimeMakeView)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(GifAnimeMakeView.ID);
						if(part!=null){
							for (int j = 0; j < exportedFiles.length; j++) {
								part.getFileList().addFile(exportedFiles[j]);	
							}
							
						}else{
							log.warn("some how cant open view");
						}
					} catch (PartInitException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				}
				addGifAnimeView=false;
			}
		}

		@Override
		public void beforeExecute() {
			files=fileList.getSelectionFiles();
			exportPath=exportDirs.getAbsoluteFilePath();
			
			if(exportType.getValue().equals("PNG")){
				isPng=true;
			}else{
				isPng=false;
			}
			jpegQuality=Float.parseFloat(jpegQualityScale.getValue())/100;
			if(clipSelect.getBoolean()){
				isClip=true;
				clipX=boundControler.getX();
				clipY=boundControler.getY();
				clipW=boundControler.getWidth();
				clipH=boundControler.getHeight();
			}else{
				isClip=false;
			}
			baseName=exportPath+"\\"+baseNameText.getText();
		}

		@Override
		public boolean canExecute() {
			// TODO Auto-generated method stub
			boolean ret= fileList.getFileList().length>0 && !exportDirs.getAbsoluteFilePath().equals("");
		
			return ret;
		}

		@Override
		public void cancelExecuting() {
			// TODO Auto-generated method stub
			
		}

		
		@Override
		public void inExecute() {
			cancelling=false;
			//validate values
			if(files==null || files.length==0){
				Akj_betasPlugin.getDefault().getProcessPrinter().printError("files empty");
				return;
			}
			
			//
			
			StatusBarUtils.showStatusBar(Messages.getString("trimmingview.start_convert"));
			List<File> exs=new ArrayList<File>();
			
			for (int i = 0; i < files.length; i++) {
				if(cancelling){
					break;
				}
				try {
					
					BufferedImage baseImage=ImageIO.read(files[i]);
					if(baseImage!=null){
						BufferedImage saveImage;
						if(isClip){
							
							saveImage=ImageUtils.clipImage(baseImage, clipX, clipY, clipW, clipH, new Color(255,255,255));
						}else{
							//same
							saveImage=ImageUtils.toRGB(baseImage);
						}
						baseImage.getGraphics().dispose();
						if(isPng){
							File exportFile=nextExportFile(baseName, "png");
							ImageIO.write(saveImage, "png", exportFile);
							exs.add(exportFile);
						}else{
							File exportFile=nextExportFile(baseName, "jpg");
							ImageUtils.writeJpegWithQuality(saveImage, exportFile, jpegQuality);
							exs.add(exportFile);
						}
						
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			exportedFiles=exs.toArray(new File[exs.size()]);
			StatusBarUtils.showStatusBar("");
			
			//some file check;
		}

		public boolean isAddGifAnimeView() {
			return addGifAnimeView;
		}

		public void setAddGifAnimeView(boolean addGifAnimeView) {
			this.addGifAnimeView = addGifAnimeView;
		}
		
	}
	
	public File nextExportFile(String baseName,String extension){
		int count=1;
		File file=null;
		do {
			String path = baseName+"_" + toDigits(count)
			+ "."+extension;
			file=new File(path);
			count++;
		}while(file.exists());
		
		
		return file;
	}
	
	private String toDigits(int value){
		String result=""+value;
		while(result.length()<4){
			result="0"+result;
		}
		return result;
	}
	
	public class CustomProcessPrinter implements ProcessPrinter{
		private String result="";
		public CustomProcessPrinter(String result){
			this.result=result;
		}
		public void printError(String error) throws IOException {
			print(error);
		}
		
		public void print(String text){
			Akj_betasPlugin.getDefault().getProcessPrinter().printOutput(text);
			String checkString="*faild*";
			if(text.indexOf(checkString)!=-1){
				result=Messages.getString("mplexviewer.faild");
			}
		}

		public void printOutput(String output) throws IOException {
			print(output);
		}

		public String getResult() {
			return result;
		}

		public void setResult(String result) {
			this.result = result;
		}
	}
	
	public class FileSelected implements FileStatusChangeListener{

		public void addList(FileStatusChangeEvent event) {
			executer.updateControlSwitch();
		}

		public void removeList(FileStatusChangeEvent event) {
			executer.updateControlSwitch();
		}
		
	}
		
}